/* eslint-disable no-unused-vars */
/* eslint-disable no-undef */
const fs = require('fs')
const path = require('path')
const amdLoader = require('../node_modules/monaco-editor/min/vs/loader.js')
const amdRequire = amdLoader.require
const { dialog } = require('electron').remote
const hexy = require('hexy')
const languageDetect = require('language-detect')
const chokidar = require('chokidar')

const hlt = require('./modules/highlight.js')

const hmUnitCount = 16
const hmUnitBytes = 2
const hmUnitSpanLength = 1
const hmUnitLength = hmUnitBytes + hmUnitSpanLength // 3

const hmAddrOffset = 1
const hmAddrLength = 10
const hmHexOffset = hmAddrOffset + hmAddrLength // 11
const hmHexLength = hmUnitLength * hmUnitCount // 16 * 3 = 48
const hmSpanOffset = hmHexOffset + hmHexLength // 59
const hmSpanLength = 3
const hmStrOffset = hmSpanOffset + hmSpanLength // 62
const hmStrLength = 16
const hmEofOffset = hmStrOffset + hmStrLength // 78

var editor
var breakpointHit = false
var breakpointAfterLines = 0
var breakpointBuff = []
var chartFrameBuff = []
var half_line = false
var ansiWait = false
var captureFileStream
var localSave = false

// tabEl -> view
// view -> {path, model, state}
var tabsMap = new Map()

// -----------------------chokidar watch section
const watcher = chokidar.watch('./a.bc', {
  ignored: /(^|[\/\\])\../, // ignore dotfiles
  persistent: true,
})

watcher.on('change', (filePath) => {
  // console.log(filePath + " content changed");
  if (true === localSave) {
    localSave = false
    return
  }
  tabsMap.forEach((view, el) => {
    if (filePath === view.path) {
      // Here we add a 100ms delay as external editor (or the watcher itself)
      // seems like first trigger the change event then will keep lock the file
      // for small amount time.
      // This will sometimes cause readFileSync or readFile return empty content and no
      // error watched.
      setTimeout(() => {
        view.model.setValue(fs.readFileSync(filePath, 'utf8'))
      }, 100)
    }
  })
})

watcher.on('unlink', (filePath) => {
  console.log(filePath + 'removed')
  tabsMap.forEach((view, el) => {
    if (filePath === view.path) {
      view.path = null
      el.children[2].children[1].style.color = '#f54336'
    }
  })
})

// ------------------------editor section
function uriFromPath(_path) {
  var pathName = path.resolve(_path).replace(/\\/g, '/')
  if (pathName.length > 0 && pathName.charAt(0) !== '/') {
    pathName = '/' + pathName
  }
  return encodeURI('file://' + pathName)
}

function openFile() {
  dialog
    .showOpenDialog({
      properties: ['openFile'],
    })
    .then((result) => {
      if (result.canceled === false) {
        const filePath = result.filePaths[0]
        // add to watcher
        watcher.add(filePath)
        // setup model theme and language
        const model = editor.getModel()
        const lang = languageDetect.filename(filePath)
        if (undefined !== lang && 'Text' !== lang) {
          monaco.editor.setModelLanguage(model, lang.toLowerCase())
        }

        // show text
        fs.readFile(filePath, 'utf8', (e, data) => {
          if (e) throw e
          editor.getModel().setValue(data)
        })

        // setup tab
        const title = path.basename(filePath)
        const el = chromeTabs.activeTabEl
        const view = tabsMap.get(el)

        // 1. setup file watcher
        if (null !== view.path) {
          watcher.unwatch(view.path)
        }
        watcher.add(filePath)
        // 2. setup tabsMap file path
        tabsMap.get(el).path = filePath
        // 3. setup title
        let titleEl = el.querySelector('.chrome-tab-title')

        el.align = 'center'
        titleEl.innerHTML = title
      }
    })
}

// ----------------------editor function section
function openFileInNewTab() {
  chromeTabs.addTab()
  openFile()
}

function openBinFile() {
  if (true !== store.get('general.hexmode')) {
    toast("Please first enable 'Hex Mode' in General tab.")
    return
  }

  dialog
    .showOpenDialog({
      properties: ['openFile'],
    })
    .then((result) => {
      if (result.canceled === false) {
        const filePath = result.filePaths[0]
        // show hex text
        editor.getModel().setValue('')
        fs.readFile(filePath, (e, data) => {
          if (e) throw err
          hexModeProcess(data, false)
        })

        // setup tab
        const title = path.basename(filePath)
        const el = chromeTabs.activeTabEl
        const view = tabsMap.get(el)
        // 1. setup file watcher
        if (null !== view.path) {
          watcher.unwatch(view.path)
        }
        watcher.add(filePath)
        // 2. setup filepath
        tabsMap.get(el).path = filePath
        // 3. setup title
        let titleEl = el.querySelector('.chrome-tab-title')
        el.align = 'center'
        titleEl.innerHTML = title
      }
    })
}

function saveFile() {
  const el = chromeTabs.activeTabEl
  const view = tabsMap.get(el)
  if (view.path !== null) {
    // has path info
    const text = editor.getModel().getValue()
    fs.writeFileSync(view.path, text)
    el.children[2].children[1].style.color = '#000000'

    // update localSave state
    localSave = true
  } else {
    // no path info
    const fileName = chromeTabs.activeTabEl.innerText

    dialog
      .showSaveDialog({
        properties: ['createDirectory'],
        defaultPath: fileName,
        filters: [{ extensions: ['log'] }],
      })
      .then((result) => {
        if (result.canceled === false) {
          // save to file
          const filePath = result.filePath
          const text = editor.getModel().getValue()
          fs.writeFileSync(filePath, text)
          // update tab's path
          view.path = filePath
          el.children[2].children[1].style.color = '#000000'
          // update tab title
          let titleEl = el.querySelector('.chrome-tab-title')
          titleEl.innerHTML = path.basename(filePath)
          // add to watcher
          watcher.add(filePath)
          // update localSave state
          localSave = true
          // update theme accord to new file extension
          const lang = languageDetect.filename(filePath)
          if (undefined !== lang && 'Text' !== lang) {
            monaco.editor.setModelLanguage(view.model, lang.toLowerCase())
          }
        }
      })
  }
}

function saveAsFile() {
  const el = chromeTabs.activeTabEl
  const view = tabsMap.get(el)
  // no path info
  const fileName = chromeTabs.activeTabEl.innerText

  dialog
    .showSaveDialog({
      properties: ['createDirectory'],
      defaultPath: fileName,
      filters: [{ extensions: ['log'] }],
    })
    .then((result) => {
      if (result.canceled === false) {
        // save to file
        const filePath = result.filePath
        const text = editor.getModel().getValue()
        fs.writeFileSync(filePath, text)
        // update tab's path
        view.path = filePath
        el.children[2].children[1].style.color = '#000000'
        // update tab title
        let titleEl = el.querySelector('.chrome-tab-title')
        titleEl.innerHTML = path.basename(filePath)
        // add to watcher
        watcher.add(filePath)
        // update localSave state
        localSave = true
        // update theme accord to new file extension
        const lang = languageDetect.filename(filePath)
        if (undefined !== lang && 'Text' !== lang) {
          monaco.editor.setModelLanguage(view.model, lang.toLowerCase())
        }
      }
    })
}

function createFileName() {
  let date = new Date()
  date = date.toString().split(' ')
  let name = date[0] + '-' + date[4].replace(/[.|:]/g, '-') + '.log'

  return name
}

function newTab() {
  chromeTabs.addTab()
}

function switchTab(tabIndex) {
  const elParent = chromeTabs.el.children[0]

  if (tabIndex >= elParent.childElementCound) return
  const el = elParent.children[tabIndex - 1]
  chromeTabs.setCurrentTab(el)
}

function getTimestamp() {
  const t = new Date()

  return (
    t.toLocaleTimeString().split(' ')[0] +
    ':' +
    t.getMilliseconds().toString().padStart(3, 0) +
    ' '
  )
}

function editorApplyEdit(textString, appendLine, revealLine) {
  const model = editor.getModel()
  const lineCount = model.getLineCount()
  let lastLineLength = 1
  if (true === appendLine) {
    lastLineLength = model.getLineMaxColumn(lineCount)
  }

  const range = new monaco.Range(
    lineCount,
    lastLineLength,
    lineCount,
    lastLineLength
  )

  editor.getModel().applyEdits([
    {
      forceMoveMarkers: true,
      range: range,
      text: textString,
    },
  ])

  if (undefined !== captureFileStream) {
    captureFileStream.write(textString)
  }

  if (true === revealLine && textDownward === true)
    editor.revealLine(model.getLineCount())
}

function hexModeProcess(buffer, revealLine) {
  const text = hexy.hexy(buffer, { format: 'twos' })
  const model = editor.getModel()
  // const lineCount = model.getLineCount();

  editorApplyEdit(text, false, revealLine)
}

function breakpointProcess(line) {
  if (breakpointHit === false) {
    let bpLine = line

    if (breakpointBuff.length !== 0) {
      bpLine = Buffer.concat(
        [breakpointBuff, line],
        line.length + breakpointBuff.length
      )
      breakpointBuff = []
    }

    if (bpLine.includes(store.get('advance.breakpoint.onText')) === true) {
      breakpointHit = true
      breakpointAfterLines = 0
    }
  } else {
    breakpointAfterLines++
    if (breakpointAfterLines >= store.get('advance.breakpoint.afterLines')) {
      breakpointHit = false
      breakpointAfterLines = 0

      return true
    }
  }

  return false
}

function filterAnsiCode(inBuffer) {
  let inArray = [...inBuffer]
  let outArray = []
  let arrayLen = inArray.length

  for (let i = 0; i < arrayLen; i++) {
    if (ansiWait === false) {
      if (0x1b !== inArray[i]) {
        // \u001b
        outArray.push(inArray[i])
      } else {
        ansiWait = true
      }
    } else {
      if (0x6d === inArray[i]) {
        // m
        ansiWait = false
      }
    }
  }

  return Buffer.from(outArray)
}

function stringModeProcess(inBuffer) {
  // 1. trim ansi escape codes
  // let buffer = filterAnsiCode(inBuffer);
  let buffer = inBuffer

  // 2. output full line
  let index = -1
  let outputTmp = buffer
  while ((index = buffer.indexOf('\n')) !== -1) {
    let line = buffer.slice(0, index + 1)

    if (half_line === true) {
      outputTmp = line
      half_line = false
    } else {
      let timestamp = ''

      if (store.get('general.timestamp') === true) timestamp = getTimestamp()
      outputTmp = timestamp + line
    }
    editorApplyEdit(
      outputTmp.toString().replace(/[^\x20-\x7E\n\r\t]/g, '.'),
      true,
      true
    )

    buffer = buffer.slice(index + 1, buffer.length)

    if (store.get('advance.breakpoint.switch') === true) {
      if (breakpointProcess(line) === true) {
        buffer = Buffer.from('')
        serialClose()
      }
    }
  }

  // 3. output partial line
  if (buffer.length !== 0) {
    if (half_line === true) {
      outputTmp = buffer
    } else {
      let timestamp = ''

      if (store.get('general.timestamp') === true) timestamp = getTimestamp()
      outputTmp = timestamp + buffer
      half_line = true
    }
    editorApplyEdit(
      outputTmp.toString().replace(/[^\x20-\x7E\n\r\t]/g, '.'),
      true,
      true
    )
  }
  if (store.get('advance.breakpoint.switch') === true) {
    breakpointBuff = buffer
  }
}

amdRequire.config({
  // eslint-disable-next-line no-undef
  baseUrl: uriFromPath(
    path.join(__dirname, '../node_modules/monaco-editor/min')
  ),
})

// workaround monaco-css not understanding the environment
self.module = undefined

amdRequire(['vs/editor/editor.main'], function () {
  monaco.languages.register({
    id: 'comNGLang',
  })
  monaco.languages.setMonarchTokensProvider('comNGLang', {
    defaultToken: '',

    tokenizer: {
      root: [
        [/^\[?[f|F][a|A][t|T][a|A][l|L]\]?\s.*/, 'fatal'],
        [/\s+\[?[f|F][a|A][t|T][a|A][l|L]\]?\s+/, 'fatal'],
        [/^\[?F\]?\s.*/, 'fatal'],
        [/\s+\[?F\]?\s+/, 'fatal'],
        [/^\[?[e|E][r|R][r|R][o|O][r|R]\]?\s.*/, 'error'],
        [/\s+\[?[e|E][r|R][r|R][o|O][r|R]\]?\s+/, 'error'],
        [/^\[?E\]?\s.*/, 'error'],
        [/\s+\[?E\]?\s+/, 'error'],
        [/^\[?[w|W][a|A][r|R][n|N]\]?\s.*/, 'warn'],
        [/\s+\[?[w|W][a|A][r|R][n|N]\]?\s+/, 'warn'],
        [/^\[?W\]?\s.*/, 'warn'],
        [/\s+\[?W\]?\s+/, 'warn'],
        [/^\[?[i|I][n|N][f|F][o|O]\]?\s.*/, 'info'],
        [/\s+\[?[i|I][n|N][f|F][o|O]\]?\s+/, 'info'],
        [/^\[?I\]?\s.*/, 'info'],
        [/\s+\[?I\]?\s+/, 'info'],
        [/^\[?[t|T][r|R][a|A][c|C][e|E]\]?\s.*/, 'trace'],
        [/\s+\[?[t|T][r|R][a|A][c|C][e|E]\]?\s+/, 'trace'],
        [/^\[?T\]?\s.*/, 'trace'],
        [/\s+\[?T\]?\s+/, 'trace'],
        [/^\[?[d|D][e|E][b|B][u|U][g|G]\]?\s.*/, 'debug'],
        [/\s+\[?[d|D][e|E][b|B][u|U][g|G]\]?\s+/, 'debug'],
        [/^\[?D\]?\s.*/, 'debug'],
        [/\s+\[?D\]?\s+/, 'debug'],

        [/\[\d;\d{2}m/, 'useless'],
        [/\[\dm/, 'useless'],

        [/[{}()[\]]/, 'bracket'],
        [/^\d{1,2}:\d{2}:\d{2}:\d{1,3}/, 'timestamp'],
        [/\d{1,4}(-|\/|\.|:)\d{1,2}\1\d{1,4}/, 'time'],
        [
          /(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)(-|\/|\.|:)(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\2(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)\2(25[0-5]|2[0-4]\d|[0-1]\d{2}|[1-9]?\d)/,
          'ip',
        ],
        [
          /[0-9a-fA-F]{2}(-|\/|\.|:)[0-9a-fA-F]{2}\1[0-9a-fA-F]{2}\1[0-9a-fA-F]{2}\1[0-9a-fA-F]{2}\1[0-9a-fA-F]{2}/,
          'mac',
        ],
        [/\d*\.\d+([eE][-+]?\d+)?/, 'number'],
        [/0[xX][0-9a-fA-F]+/, 'number'],
        [/[0-9a-fA-F]{4,}/, 'number'],
        [/\d+/, 'number'],
      ],
    },
  })

  // Define a new theme that contains only rules that match this language
  monaco.editor.defineTheme('comNGTheme', {
    base: 'vs',
    inherit: true,
    rules: [
      { token: 'number', foreground: '2e7d32' },
      { token: 'bracket', foreground: 'ff9800' },
      { token: 'timestamp', foreground: '009688' },
      { token: 'time', foreground: '2196f3' },
      { token: 'ip', foreground: '03a9f4' },
      { token: 'mac', foreground: '00bcd4' },
      { token: 'fatal', foreground: 'e91e63' },
      { token: 'error', foreground: 'f44336' },
      { token: 'warn', foreground: 'ff9800' },
      { token: 'info', foreground: '9e9e9e' },
      { token: 'trace', foreground: '9e9d24' },
      { token: 'debug', foreground: '2e7d32' },
      { token: 'useless', foreground: 'cecece' },
    ],
  })

  let readOnlyEditor = false
  if (true === store.get('general.hexmode')) {
    readOnlyEditor = true
  }
  editor = monaco.editor.create(document.getElementById('editor-area'), {
    model: null,
    theme: 'comNGTheme',
    language: 'comNGLang',
    automaticLayout: true,
    readOnly: readOnlyEditor,
    folding: false,
    fontFamily: store.get('general.fontFamily'),
    fontSize: store.get('general.fontSize'),
    overviewRulerBorder: false,
    scrollBeyondLastLine: false,
    smoothScrolling: true,
    mouseWheelZoom: true, // combined with Ctrl
    wordWrap: 'on',
    wordWrapBreakAfterCharacters: '',
    wordWrapBreakBeforeCharacters: '',
    lineNumbersMinChars: 4,
    // minimap: {
    //   enabled: false,
    // },
    scrollbar: {
      vertical: 'auto',
      useShadows: false,
      verticalScrollbarSize: 10,
    },
  })

  let editorConfig = {
    brackets: [
      ['{', '}'],
      ['[', ']'],
      ['(', ')'],
      ['"', '"'],
      ["'", "'"],
    ],
  }
  monaco.languages.setLanguageConfiguration('comNGLang', editorConfig)

  editor.addAction({
    id: 'highlight-toggle',
    label: 'Highlight Toggle',
    keybindings: [monaco.KeyMod.CtrlCmd + monaco.KeyCode.KEY_E],
    precondition: null,
    keybindingContext: null,
    contextMenuGroupId: '9_cutcopypaste',
    contextMenuOrder: 3.5,
    run: hlt.toggle,
  })

  editor.addAction({
    id: 'highlight-clear-all',
    label: 'Highlight Clear All',
    keybindings: [
      monaco.KeyMod.CtrlCmd + monaco.KeyMod.Shift + monaco.KeyCode.KEY_E,
    ],
    precondition: null,
    keybindingContext: null,
    contextMenuGroupId: '9_cutcopypaste',
    contextMenuOrder: 3.6,
    run: hlt.clear,
  })

  editor.addCommand(monaco.KeyMod.CtrlCmd + monaco.KeyCode.KEY_W, () => {
    // Do nothing but prevent default action: close window
  })

  // editor.addCommand(monaco.KeyMod.CtrlCmd + monaco.KeyCode.KEY_X, () => {
  //   // Do nothing but prevent default action: close window
  // });

  function getLinePairRange(range) {
    let s = range.startColumn
    if (s <= hmSpanOffset) {
      // hex area
      if (s < hmHexOffset) s = range.startColumn = hmHexOffset
      s = Math.round((s - hmHexOffset) / hmUnitLength) + hmStrOffset
    } else {
      // str area
      if (s < hmStrOffset) s = range.startColumn = hmStrOffset
      s = (s - hmStrOffset) * hmUnitLength + hmHexOffset
    }

    let e = range.endColumn
    if (e <= hmStrOffset) {
      // hex area
      if (e < hmHexOffset) e = range.endColumn = hmHexOffset
      if (e > hmSpanOffset) e = range.endColumn = hmSpanOffset
      e = Math.round((e - hmHexOffset) / hmUnitLength) + hmStrOffset
    } else {
      // str area
      if (e < hmStrOffset) e = range.endColumn = hmStrOffset
      e = (e - hmStrOffset) * hmUnitLength + hmHexOffset
    }

    return new monaco.Range(range.startLineNumber, s, range.startLineNumber, e)
  }

  function showCursors(model, range) {
    let cordRange = getLinePairRange(range)
    if (undefined === cordRange) return

    // first remove old decos
    let decos = model.getLineDecorations(range.startLineNumber)
    for (let deco of decos) {
      if (deco.options.className === 'hex-cursor') {
        model.deltaDecorations([deco.id], [])
      }
    }

    model.deltaDecorations(
      [],
      [
        {
          range: range,
          options: {
            className: 'hex-cursor',
            zIndex: 999,
          },
        },
        {
          range: cordRange,
          options: {
            className: 'hex-cursor',
            zIndex: 999,
            overviewRuler: {
              color: '#f06292',
              position: 4, // 2: center, 4: right, 1: left, 7: full
            },
          },
        },
      ]
    )
  }

  function selectRanges(model, range, pairRange, decoration) {
    // first remove old decos
    let decos = model.getLineDecorations(range.startLineNumber)
    let zIndex = 1
    for (let deco of decos) {
      if (
        deco.options.className !== null &&
        deco.options.className.indexOf('hl-') !== -1
      ) {
        if (deco.options.zIndex >= zIndex) zIndex = deco.options.zIndex + 1
      }
    }

    // then apply new decos
    model.deltaDecorations(
      [],
      [
        {
          range: range,
          options: {
            className: decoration.style,
            zIndex: zIndex,
          },
        },
        {
          range: pairRange,
          options: {
            className: decoration.style,
            zIndex: zIndex,
            overviewRuler: {
              color: decoration.color,
              position: 4, // 2: center, 4: right, 1: left, 7: full
            },
          },
        },
      ]
    )
  }

  function extracLineRange(range, line) {
    let s = (e = 1)

    if (line === range.startLineNumber) {
      s = range.startColumn
      if (s <= hmSpanOffset) {
        // hex area
        if (range.startLineNumber !== range.endLineNumber) e = hmSpanOffset
        else e = range.endColumn
      } else {
        // str area
        if (range.startLineNumber !== range.endLineNumber) e = hmEofOffset
        else e = range.endColumn
      }
    } else if (line === range.endLineNumber) {
      e = range.endColumn
      if (e <= hmStrOffset) {
        // hex area
        if (range.startLineNumber !== range.endLineNumber) s = hmHexOffset
        else s = range.startColumn
      } else {
        // str area
        if (range.startLineNumber !== range.endLineNumber) s = hmStrOffset
        else
          s = range.startColumn > hmStrOffset ? range.startColumn : hmStrOffset
      }
    } else {
      // default hex area
      s = hmHexOffset
      e = hmSpanOffset
    }

    return new monaco.Range(line, s, line, e)
  }

  editor.onMouseUp(() => {
    if (false === store.get('general.hexmode')) return

    let model = editor.getModel()
    let range = editor.getSelection()
    console.log('In: ' + range)

    if (range.isEmpty() === true) {
      showCursors(model, range)
    } else {
      let deco = hlt.decoGet()
      for (
        let line = range.startLineNumber;
        line <= range.endLineNumber;
        line++
      ) {
        let lineRange = extracLineRange(range, line)
        let linePairRange = getLinePairRange(lineRange)
        selectRanges(model, lineRange, linePairRange, deco)
      }
    }
  })

  // --------------------------Chrometabs section, refer to:
  // https://stackoverflow.com/questions/38266951/how-to-create-chrome-like-tab-on-electron
  const tabsEl = document.getElementById('tabs-area')

  tabsEl.addEventListener('tabAdd', ({ detail }) => {
    // console.log("tab add");
    navigator_layout_update()

    // create a new model
    let model = monaco.editor.createModel()
    editor.setModel(model)
    monaco.editor.setModelLanguage(model, 'comNGLang')

    let el = detail.tabEl
    // setup the title with time
    let title = createFileName()
    let titleEl = el.querySelector('.chrome-tab-title')
    el.align = 'center'
    titleEl.innerHTML = title

    // setup content change listener for model
    model.onDidChangeContent((e) => {
      // console.log(e);
      if (e.isFlush === true) return
      el.children[2].children[1].style.color = '#26a69a'
    })

    // setup the map between table and model/state
    let view = {
      model: model,
      path: null,
      state: null,
    }
    tabsMap.set(el, view)
  })

  tabsEl.addEventListener('activeTabChange', ({ detail }) => {
    let el = detail.tabEl

    // Save before tab's state
    let model = editor.getModel()
    tabsMap.forEach((view, _) => {
      if (model === view.model) {
        view.state = editor.saveViewState()
      }
    })

    // Restore new tab's state
    let view = tabsMap.get(el)
    editor.setModel(view.model)
    editor.restoreViewState(view.state)
  })

  tabsEl.addEventListener('tabRemove', ({ detail }) => {
    // console.log("tab remove");
    navigator_layout_update()

    // delete from watcher
    const view = tabsMap.get(detail.tabEl)
    if (null !== view.path) {
      watcher.unwatch(view.path)
    }

    // delete from tabsMap
    tabsMap.delete(detail.tabEl)
    if (0 === tabsMap.size) chromeTabs.addTab()
  })

  chromeTabs.init(tabsEl)
  chromeTabs.addTab()
  document.getElementById('tab-add-btn').onclick = () => {
    chromeTabs.addTab()
  }

  return editor
})

document.getElementById('clear-btn').onclick = () => {
  let value = ''

  if (store.get('advance.sign.switch') === true) {
    value =
      '------This file captured at ' +
      new Date().toLocaleString() +
      ' with comNG'
    if (store.get('advance.sign.name') !== '')
      value += ' by ' + store.get('advance.sign.name') + '.------'
    else value += '.------'
    value += '\n'
  }

  hexmodeIndex = 0
  editor.getModel().setValue(value)
}

document.getElementById('editor-font-family').onblur = (e) => {
  let font = e.target.value.trim()

  if (font === '') font = defaultFont
  editor.updateOptions({ fontFamily: font })
  store.set('general.fontFamily', font)
}

document.getElementById('editor-font-size').onblur = (e) => {
  let size = e.target.value.trim()
  if (size === '') size = 12

  editor.updateOptions({ fontSize: size })
  store.set('general.fontSize', size)
}

document.getElementById('breakpoint-switch').onclick = (e) => {
  if (e.target.checked === true) {
    if (store.get('advance.breakpoint.onText.length') === 0) {
      toast('Error: Breakpoint on-text cant be empty')
      e.target.checked = false
      return
    }
  }

  store.set('advance.breakpoint.switch', e.target.checked)
  breakpointHit = false
  breakpointAfterLines = 0
}

document.getElementById('breakpoint-on-text').onblur = (e) => {
  store.set('advance.breakpoint.onText', e.target.value)
}

document.getElementById('breakpoint-after-lines').onblur = (e) => {
  let lines = parseInt(e.target.value)

  if (isNaN(lines) === true) lines = 5
  store.set('advance.breakpoint.afterLines', lines)
}

document.getElementById('capture-file-switch').onclick = (e) => {
  if (e.target.checked === true) {
    let fileName = createFileName()

    dialog
      .showSaveDialog({
        properties: ['createDirectory'],
        defaultPath: fileName,
        filters: [{ extensions: ['log'] }],
      })
      .then((result) => {
        let pathEle = document.getElementById('capture-file-path')
        if (result.canceled === false) {
          let filePath = result.filePath
          pathEle.value = filePath
          captureFileStream = fs.createWriteStream(filePath, { flags: 'w' })

          store.set('fileops.capture.switch', true)
          store.set('fileops.capture.filePath', filePath)
        } else {
          if (undefined !== captureFileStream) captureFileStream.end()
          captureFileStream = undefined
          pathEle.value = ''

          store.set('fileops.capture.switch', false)
          store.set('fileops.capture.filePath', '')

          // restore check status
          e.target.checked = false
        }
      })
  } else {
    if (undefined !== captureFileStream) captureFileStream.end()
    captureFileStream = undefined

    store.set('fileops.capture.switch', false)
  }
}

document.getElementById('capture-file-path').ondblclick = (e) => {
  const file = e.target.value
  const text = fs.readFileSync(file).toString()
  editor.getModel().setValue(text)
}

document.getElementById('editor-area').ondragover = () => {
  return false
}

document.getElementById('editor-area').ondragleave = () => {
  return false
}

document.getElementById('editor-area').ondragend = () => {
  return false
}

document.getElementById('editor-area').ondrop = (e) => {
  console.log('ondrop')
  e.preventDefault()

  let f = e.dataTransfer.files[0]

  f.text().then((text) => {
    editor.getModel().setValue(text)
  })

  return false
}

function editorStateReset() {
  breakpointHit = false
  breakpointAfterLines = 0
  breakpointBuff = []
  half_line = false
  ansiWait = false

  hlt.reset()
}
